/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */

package EntityPack;

import MapPack.Cell;
import MaterialPack.Fluid;
import MapPack.Map;
import ToolPack.FluidContainer;
import com.badlogic.gdx.graphics.Texture;

import java.util.ArrayList;

/**
 *
 * @author Aaron
 */

public abstract class Entity {

    // The lower-left position.
    protected Cell position;
    protected Map map;
    protected final boolean tangible;
    protected final int height;
    protected final int width;
    protected ArrayList<FluidContainer> containers;

    protected Entity (int height, int width, boolean tangible) {
        this.height = height;
        this.width = width;
        this.tangible = tangible;
        this.containers = new ArrayList<>();
    }

    protected Entity (Map map, Cell position) {
        this(map, 1, 1, position, true);
    }

    protected Entity (Map map, int height, int width, Cell position, boolean tangible) {
        this.map = map;
        this.height = height;
        this.width = width;
        this.setPosition(position);
        this.tangible = tangible;
        this.containers = new ArrayList<>();
    }

    final public Cell getPosition ( ) {
        return this.position;
    }

    // All position changes go through this method.
    final public boolean setPosition (Cell newPos) {
        if (this.map == null) {
            return false;
        }

        Cell tempCell;

        // Check the future cells for tangible entities or impassable terrain.
        for (int x = 0; x < this.width; x++) {
            for (int y = 0; y < this.height; y++) {
                tempCell = this.map.getMapCell(newPos.getX() + x, newPos.getY() + y);
                if (this.tangible) {
                    if (tempCell.getEntities().stream().anyMatch(e -> e.tangible == true)
                            || !newPos.isPassable()) {
                        return false;
                    }
                }
            }
        }

        // Remove this entity from all current cells.
        if (this.position != null) {
            for (int x = 0; x < this.width; x++) {
                for (int y = 0; y < this.height; y++) {
                    tempCell = this.map.getMapCell(this.position.getX() + x, this.position.getY() + y);
                    tempCell.removeEntity(this);
                }
            }
        }

        // Move this entity to its new cells.
        for (int x = 0; x < this.width; x++) {
            for (int y = 0; y < this.height; y++) {
                tempCell = this.map.getMapCell(newPos.getX() + x, newPos.getY() + y);
                tempCell.addEntity(this);
            }
        }

        this.position = newPos;

        return true;
    }

    final public int getX ( ) {
        return Math.round(this.position.getX());
    }

    final public boolean setX (int x) {
        if (this.map == null) {
            return false;
        }

        boolean result = false;
        Cell potentialPosition = this.map.getMapCell(x, this.getY());

        if (potentialPosition != null) {
            return this.setPosition(potentialPosition);
        }

        return result;
    }

    final public int getY ( ) {
        return Math.round(this.position.getY());
    }

    final public boolean setY (int y) {
        if (this.map == null) {
            return false;
        }

        boolean result = false;
        Cell potentialPosition = this.map.getMapCell(this.getX(), y);

        if (potentialPosition != null) {
            result = this.setPosition(potentialPosition);
        }

        return result;
    }

    final public void removeFromMap ( ) {
        this.position.removeEntity(this);
        this.position = null;
        this.map = null;
    }

    abstract public Texture getTexture ( );

    public FluidContainer findNonEmptyContainer (Class<? extends Fluid> fluidType) {
        FluidContainer result = null;
        for (FluidContainer container : this.containers) {
            if (container.getFluidType().equals(fluidType) && container.getFluid() > 0) {
                result = container;
            }
        }

        return result;
    }

    public FluidContainer findEmptyContainer (Class<? extends Fluid> fluidType) {
        FluidContainer result = null;
        for (FluidContainer container : this.containers) {
            if (container.getFluidType().equals(fluidType) && container.getFluid() == 0) {
                result = container;
            }
        }

        return result;
    }

    public FluidContainer findContainer (Class<? extends Fluid> fluidType) {
        FluidContainer result = null;
        for (FluidContainer container : this.containers) {
            if (container.getFluidType().equals(fluidType)) {
                result = container;
            }
        }

        return result;
    }

    public ArrayList<FluidContainer> getContainers ( ) {
        return this.containers;
    }
}
